<script setup>
import { onMounted, ref } from 'vue';

const props = defineProps({
  img: { type: String, default: '' },
  tool: { type: String, default: 'pencil' },
  brushSize: { type: Number, default: 50 },
});

const container = ref(null);
const mainCanvas = ref(null);
const maskCanvas = ref(null);

// 动态宽高
const canvasSize = ref({ width: 0, height: 0 });
// 图片及绘制信息
const imageDrawInfo = ref({
  offsetX: 0,
  offsetY: 0,
  drawWidth: 0,
  drawHeight: 0,
  scaleX: 1,
  scaleY: 1,
  originalWidth: 0,
  originalHeight: 0,
});

let mainCtx = null;
let maskCtx = null;
let isDrawing = false;
const cursor = ref({ x: 0, y: 0, visible: false });

onMounted(() => {
  mainCtx = mainCanvas.value.getContext('2d');
  maskCtx = maskCanvas.value.getContext('2d');

  const ro = new ResizeObserver((entries) => {
    entries.forEach(({ contentRect }) => {
      const { width, height } = contentRect;
      canvasSize.value = { width, height };
      [mainCanvas.value, maskCanvas.value].forEach(
        (c) => c && ((c.width = width), (c.height = height)),
      );
      loadAndDrawImage(width, height);
    });
  });
  ro.observe(container.value);
});

function loadAndDrawImage(width, height) {
  const imgEl = new Image();
  imgEl.crossOrigin = 'anonymous';
  imgEl.src = props.img;
  imgEl.addEventListener('load', () => {
    mainCtx.clearRect(0, 0, width, height);
    const oH = imgEl.height;
    const oW = imgEl.width;
    const canvasRatio = width / height;
    const imgRatio = oW / oH;
    const drawW = imgRatio > canvasRatio ? width : height * imgRatio;
    const drawH = imgRatio > canvasRatio ? width / imgRatio : height;
    const offsetX = (width - drawW) / 2;
    const offsetY = (height - drawH) / 2;
    imageDrawInfo.value = {
      offsetX,
      offsetY,
      drawWidth: drawW,
      drawHeight: drawH,
      scaleX: drawW / oW,
      scaleY: drawH / oH,
      originalWidth: oW,
      originalHeight: oH,
    };
    mainCtx.drawImage(imgEl, offsetX, offsetY, drawW, drawH);
    maskCtx.clearRect(0, 0, width, height);
  });
}

// 优化：事件中实时计算容器边界，避免缓存失效
function getCoords(event) {
  const rect = maskCanvas.value.getBoundingClientRect();
  return { x: event.clientX - rect.left, y: event.clientY - rect.top };
}

function requestDraw(x, y) {
  requestAnimationFrame(() => {
    maskCtx.lineTo(x, y);
    maskCtx.stroke();
  });
}

const startDraw = (e) => {
  isDrawing = true;
  maskCtx.globalCompositeOperation =
    props.tool === 'eraser' ? 'destination-out' : 'source-over';
  maskCtx.strokeStyle =
    props.tool === 'eraser' ? 'rgba(0,0,0,1)' : 'rgba(255,255,0,1)';
  maskCtx.lineWidth = props.brushSize;
  maskCtx.lineCap = 'round';

  const { x, y } = getCoords(e);
  maskCtx.beginPath();
  maskCtx.moveTo(x, y);
};

const draw = (e) => {
  if (!isDrawing) return;

  // 获取相对于绘制区域的坐标
  const { offsetX, offsetY, drawWidth, drawHeight } = imageDrawInfo.value;
  const { x, y } = getCoords(e);

  // 计算相对区域的位置
  const relX = x - offsetX;
  const relY = y - offsetY;

  // 边界检查：相对坐标需在[0, drawWidth]和[0, drawHeight]范围内
  if (relX < 0 || relY < 0 || relX > drawWidth || relY > drawHeight) return;

  requestDraw(x, y);
};

const endDraw = () => {
  if (!isDrawing) return;
  isDrawing = false;
  maskCtx.closePath();
  exportMaskAsPNG();
};

const onMouseMove = (e) => {
  const { x, y } = getCoords(e);
  cursor.value = { x, y, visible: true };
  draw(e);
};

const handleMouseLeave = () => {
  if (isDrawing) maskCtx.closePath();
  isDrawing = false;
  cursor.value.visible = false;
};

const previewImage = ref(null);
function exportMaskAsPNG() {
  const {
    offsetX,
    offsetY,
    drawWidth,
    drawHeight,
    originalWidth,
    originalHeight,
  } = imageDrawInfo.value;
  const off = document.createElement('canvas');
  off.width = originalWidth;
  off.height = originalHeight;
  const ctx = off.getContext('2d');
  ctx.drawImage(
    maskCanvas.value,
    offsetX,
    offsetY,
    drawWidth,
    drawHeight,
    0,
    0,
    originalWidth,
    originalHeight,
  );
  const data = ctx.getImageData(0, 0, originalWidth, originalHeight).data;
  for (let i = 0; i < data.length; i += 4) {
    const a = data[i + 3];
    const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
    if (a && avg > 100) data[i] = data[i + 1] = data[i + 2] = data[i + 3] = 255;
    else (data[i] = data[i + 1] = data[i + 2] = 0), (data[i + 3] = 255);
  }
  ctx.putImageData(new ImageData(data, originalWidth, originalHeight), 0, 0);
  previewImage.value = off.toDataURL('image/png');
}

defineExpose({ getMask: () => previewImage.value });
</script>

<template>
  <div
    ref="container"
    class="product-canvas-container"
    @mousedown="startDraw"
    @mousemove="onMouseMove"
    @mouseup="endDraw"
    @mouseleave="handleMouseLeave"
  >
    <canvas
      ref="mainCanvas"
      class="canvas-layer"
      :width="canvasSize.width"
      :height="canvasSize.height"
    ></canvas>
    <canvas
      ref="maskCanvas"
      class="canvas-layer"
      :width="canvasSize.width"
      :height="canvasSize.height"
      style="opacity: 0.5"
    ></canvas>
    <div
      v-if="cursor.visible"
      class="cursor-indicator"
      :style="{
        top: `${cursor.y}px`,
        left: `${cursor.x}px`,
        width: `${props.brushSize}px`,
        height: `${props.brushSize}px`,
      }"
    ></div>
  </div>
  <!-- <div v-if="previewImage" class="h-full w-full">
    <img :src="previewImage" class="h-full w-full object-contain" />
  </div> -->
</template>

<style scoped>
.product-canvas-container {
  @apply w-4/5 aspect-square relative select-none overflow-hidden mx-auto;
  max-width: 800px;
  min-width: 300px;
}

.canvas-layer {
  @apply absolute w-full h-full top-0 left-0;
  border-radius: calc(var(--radius) - 2px);
}

.cursor-indicator {
  @apply absolute rounded-full border-2 border-primary pointer-events-none;
  transform: translate(-50%, -50%);
  z-index: 9999;
  box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
}

/* 暗色模式适配 */
:global(.dark) .cursor-indicator {
  @apply border-primary/80;
  box-shadow: 0 0 8px rgba(255, 255, 255, 0.2);
}

/* 响应式设计 */
@media (max-width: 768px) {
  .product-canvas-container {
    @apply w-full;
    max-width: none;
  }
}

@media (max-width: 640px) {
  .product-canvas-container {
    @apply w-full;
    min-width: 250px;
  }
}
</style>
